package ru.amse.tsyganov.jumleditor.main;

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;

import ru.amse.tsyganov.jumleditor.commands.ViewsManager;
import ru.amse.tsyganov.jumleditor.graphicaleditor.GraphicalEditor;
import ru.amse.tsyganov.jumleditor.graphicaleditor.ItemsSelectionListener;
import ru.amse.tsyganov.jumleditor.model.ActivityGraph;
import ru.amse.tsyganov.jumleditor.properties.PropertiesTable;
import ru.amse.tsyganov.jumleditor.storing.Storage;
import ru.amse.tsyganov.jumleditor.validator.Problem;
import ru.amse.tsyganov.jumleditor.validator.ProblemSelectionListener;
import ru.amse.tsyganov.jumleditor.validator.ProblemsList;
import ru.amse.tsyganov.jumleditor.validator.ProblemsTable;
import ru.amse.tsyganov.jumleditor.validator.Validator;
import ru.amse.tsyganov.jumleditor.view.ActivityGraphView;
import ru.amse.tsyganov.jumleditor.view.ModelChangeListener;
import ru.amse.tsyganov.jumleditor.view.SelectedItems;

public class Editor {
	
	class ActivityGraphChangeListener implements ModelChangeListener {
		
		private final ActivityGraphView<? extends ActivityGraph> activityGraphView;
		
		public ActivityGraphChangeListener(
				ActivityGraphView<? extends ActivityGraph> activityGraphView) {
			
			this.activityGraphView = activityGraphView;
		}
		
		public void modelChanged(ActivityGraph activityGraph) {
			ProblemsList probems = Validator.validate(activityGraphView);
			probems.addProblemSelectionListener(problemSelectionListener);
			problemsTable.setSource(probems);
		}
		
	}
	
	private static final String SHELL_CAPTION = "Editor";
		
	private static final int INITIAL_SHELL_WIDTH = 500;
	
	private static final int INITIAL_SHELL_HEIGHT = 500;
	
	private static final int PROPERTIES_TABLE_HEIGHT = 150;
		
	private final Display display;
	
	private final Shell sShell;
	
	private final GraphicalEditor graphicalEditor;
	
	private final ViewsManager viewsManager;
	
	private final TabFolder tabFolder; 
	
	private final PropertiesTable propertiesTable;
	
	private final ProblemsTable problemsTable;
	
	private final Composite composite;
	
	private final Menu menu;
	
	private final ItemsSelectionListener itemsSelectionListener = 
		new ItemsSelectionListener() {

			public void selectedItemsChanged(SelectedItems selectedItems) {
				if (selectedItems.selectedStatesSize() + 
						selectedItems.selectedTransitionsSize() == 1) {
					
					if (selectedItems.selectedStatesSize() == 1) {
						propertiesTable.setSource(
							selectedItems.getSelectedStates().
								iterator().next());
					}
					
					if (selectedItems.selectedTransitionsSize() == 1) {
						propertiesTable.setSource(
							selectedItems.getSelectedTransitions().
								iterator().next());
					}
				} else {
					propertiesTable.clear();
				}
			}
		
		};
		
	private final ProblemSelectionListener problemSelectionListener = 
		new ProblemSelectionListener() {

		public void problemSelected(Problem p) {
			graphicalEditor.setSelectedItems(p.getProblemPlace());
		}
		
	};
			
	public Editor(ActivityGraphView<ActivityGraph> activityGraphView) {
				
		display = new Display();
		
		sShell = new Shell(display);
		
		final int VIEWS_MANAGER_SIZE = 20; 
		viewsManager = new ViewsManager(VIEWS_MANAGER_SIZE);
		
		composite = new Composite(sShell, SWT.NONE);
		
		graphicalEditor = new GraphicalEditor(composite, activityGraphView, viewsManager);
		
		tabFolder = new TabFolder(composite, SWT.NONE);
		
		propertiesTable = new PropertiesTable(tabFolder, 
				INITIAL_SHELL_WIDTH - 20, viewsManager);
		
		problemsTable = new ProblemsTable(tabFolder, INITIAL_SHELL_WIDTH - 20);
		
		menu = new Menu(sShell, SWT.BAR);
		
		sShell.setMenuBar(menu);
		
		initMenu();
		
		createSShell();
				
		bindActivityGraphView(activityGraphView);
		
		openAndWaitEvents();
	}

	private void bindActivityGraphView(ActivityGraphView<ActivityGraph> activityGraphView) {
		
		activityGraphView.getModel().addModelChangeListener(
				new ActivityGraphChangeListener(activityGraphView));
		
		ProblemsList probems = Validator.validate(activityGraphView);
		probems.addProblemSelectionListener(problemSelectionListener);
		problemsTable.setSource(probems);
		
		graphicalEditor.addSelectionListener(itemsSelectionListener);
	}

	private void openAndWaitEvents() {
		sShell.open();
		
		while(!sShell.isDisposed()) {
		   if(!display.readAndDispatch()) {
		       display.sleep();
		   }
		}
		display.dispose();
	}

	private void createSShell() {
		
		sShell.setText(SHELL_CAPTION);
		sShell.setImage(new Image(null, "icons/activityDiagram_on.gif"));
		
		initGraphicalEditor();
		initPropertiesTable();
		initProblemsTable();
		
		FormLayout compositeFormLayout = new FormLayout();
		compositeFormLayout.marginHeight = 0;
		compositeFormLayout.marginWidth = 0;
		compositeFormLayout.marginBottom = 0;
		compositeFormLayout.marginLeft = 0;
		compositeFormLayout.marginRight = 0;
		compositeFormLayout.marginTop = 0;
		composite.setLayout(compositeFormLayout);
		
		sShell.setLayout(new FillLayout());
				
		sShell.setSize(new Point(INITIAL_SHELL_WIDTH, 
				INITIAL_SHELL_HEIGHT));
		
		assert sShell != null;
	}

	private void initGraphicalEditor() {
		assert sShell != null;
		
		FormData graphicalEditorFormData = new FormData();
		graphicalEditorFormData.left = new FormAttachment(0, 0);
		graphicalEditorFormData.right = new FormAttachment(100, 0);
		graphicalEditorFormData.bottom = new FormAttachment(100, -PROPERTIES_TABLE_HEIGHT);
		graphicalEditorFormData.top = new FormAttachment(0, 0);
		graphicalEditor.setLayoutData(graphicalEditorFormData);
	
	}
	
	private void initPropertiesTable() {
		assert sShell != null;
		assert propertiesTable != null;

		TabItem tabItem = new TabItem(tabFolder, SWT.NONE);
		tabItem.setControl(propertiesTable.getTable());
		tabItem.setText("Properties");
		
		FormData tabFolderFormData = new FormData();
		tabFolderFormData.left = new FormAttachment(0, 0);
		tabFolderFormData.right = new FormAttachment(100, 0);
		tabFolderFormData.bottom = new FormAttachment(100, 0);
		tabFolderFormData.top = new FormAttachment(graphicalEditor, 0);
		tabFolder.setLayoutData(tabFolderFormData);	
	}
	
	private void initProblemsTable() {
		assert sShell != null;
		assert problemsTable != null;
		
		TabItem tabItem = new TabItem(tabFolder, SWT.NONE);
		tabItem.setControl(problemsTable.getTable());
		tabItem.setText("Problems");
	}
	
	private void initMenu() {
		MenuItem fileMenuItem = new MenuItem(menu, SWT.CASCADE);
		fileMenuItem.setText("&File");
		
		Menu fileMenu = new Menu(sShell, SWT.DROP_DOWN);
		fileMenuItem.setMenu(fileMenu);
		
		MenuItem newMenuItem = new MenuItem(fileMenu, SWT.PUSH);
		newMenuItem.setText("&New\tCtrl+N");
		newMenuItem.setAccelerator(SWT.CTRL + 'N');
		
		MenuItem openMenuItem = new MenuItem(fileMenu, SWT.PUSH);
		openMenuItem.setText("&Open\tCtrl+O");
		openMenuItem.setAccelerator(SWT.CTRL + 'O');
		
		new MenuItem(fileMenu, SWT.SEPARATOR);
		
		MenuItem saveMenuItem = new MenuItem(fileMenu, SWT.PUSH);
		saveMenuItem.setText("&Save\tCtrl+S");
		saveMenuItem.setAccelerator(SWT.CTRL + 'S');
		
		MenuItem saveAsMenuItem = new MenuItem(fileMenu, SWT.PUSH);
		saveAsMenuItem.setText("Save &As...");
		
		new MenuItem(fileMenu, SWT.SEPARATOR);
		
		MenuItem exitMenuItem = new MenuItem(fileMenu, SWT.PUSH);
		exitMenuItem.setText("E&xit\tCtrl+X");
		exitMenuItem.setAccelerator(SWT.CTRL + 'X');
		
		exitMenuItem.addSelectionListener(new SelectionListener() {

			public void widgetDefaultSelected(SelectionEvent e) {
				widgetSelected(e);
			}

			public void widgetSelected(SelectionEvent e) {
				sShell.close();
			}
			
		});
		
		openMenuItem.addSelectionListener(new SelectionListener() {
			
			public void widgetDefaultSelected(SelectionEvent e) {
				widgetSelected(e);
			}

			public void widgetSelected(SelectionEvent e) {
				try {
					ActivityGraphView<ActivityGraph> activityGraphView = 
						Storage.read("probe.xml");
					
					graphicalEditor.setActivityGraphView(activityGraphView);
					bindActivityGraphView(activityGraphView);
				} catch (Exception e1) {
					e1.printStackTrace();
				} 
			}
		});
		
		saveMenuItem.addSelectionListener(new SelectionListener() {

			public void widgetDefaultSelected(SelectionEvent e) {
				widgetSelected(e);
			}

			public void widgetSelected(SelectionEvent e) {
				try {
					Storage.write(graphicalEditor.getActivityGraphView(), "probe.xml");
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} catch (ParserConfigurationException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} catch (TransformerException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
			
		});
	}
	
}
